require 'active_support/core_ext/object'
require 'nokogiri'
require 'postrank-uri'

class Canonizer
  @strategies = {
    'Canonical Link Tag' => ->(doc, http, url) {
      doc.css('[rel="canonical"]').first.try(:attr, 'href')
    },
    'OpenGraph Tag' => ->(doc, http, url) {
      doc.css('[property="og:url"]').first.try(:attr, 'content')
    },
    'Facebook Like Button URL' => ->(doc, http, url) {
      doc.css('[data-href][data-show-faces][data-layout]').first.try(:attr, 'data-href')
    },
    'Facebook Comment Stream URL' => ->(doc, http, url) {
      doc.css('[data-href][data-num-posts]').first.try(:attr, 'data-href')
    },
    'Last url redirect' => ->(doc, http, url) {
      result = http.last_effective_url.to_s.sub(/:(443|80)\//, '/')
      result == url ? nil : result
    },
    'Postrank URL Clean-Up' => ->(doc, http, url) {
      clean(url) == url ? nil : clean(url)
    }
  }

  def self.perform(input_url)
    http = EM::HttpRequest.new(input_url).get(redirects: 10)
    doc = Nokogiri::HTML(http.response)

    @strategies.each_pair do |description, performer|
      if result = performer.call(doc, http, input_url)
        return { strategy: description, result: clean(result) }
      end
    end

    { error: 'No canonical url found.' }
  end

  def self.clean(url)
    PostRank::URI.clean url
  end
end
